package com.wanger.swa.dto.dataSource.inf;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.wanger.swc.config.dataInstance.DataInstanceDispatcher;
import com.wanger.swc.config.dataInstance.DataInstanceService;
import com.wanger.swc.config.myBatisPlus.autoDDL.AutoDDLDispatcher;
import com.wanger.swc.config.myBatisPlus.autoDDL.AutoDDLService;
import com.wanger.swc.exception.BusEx;
import com.wanger.swa.domain.myEnum.DataSourceEnum;
import com.wanger.swa.domain.po.DataSourcePO;
import com.wanger.swa.dto.dataSource.resp.SupportTypeResp;
import com.wanger.swc.model.tips.TipInfo;
import com.wanger.swc.util.validation.MyVerifyUtil;
import lombok.extern.slf4j.Slf4j;
import org.anyline.data.datasource.DataSourceHolder;
import org.anyline.metadata.type.DatabaseType;
import org.anyline.proxy.ServiceProxy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: wanger
 * @Date: 2025/1/1 22:49
 * @Description: 虽然数据结构与数据实例都有很多共性，但不能将entity移动到common模块，为此，使用当前调度器类，以解决数据结构与数据实例之间的所以差异性
 * 1.对外提供支持的数据类型
 * 2.入参为DataSourcePO实现数据验证
 * 3.入参为DataSourcePO实现数据转换
 */
@Slf4j
@Component
public class DataSourceDispatch implements SWDataSource {
    @Resource
    private AutoDDLDispatcher autoDDLDispatcher;
    @Resource
    private DataInstanceDispatcher dataInstanceDispatcher;

    /**
     * 获取支持的数据源类型
     *
     * @return 支持的数据源类型
     */
    public List<SupportTypeResp> getSupportType() {
        SupportTypeResp structureType = new SupportTypeResp(
                new TipInfo(DataSourceEnum.STRUCTURE.getValue(), DataSourceEnum.STRUCTURE.getLabel()),
                autoDDLDispatcher.uiSupportType());
        List<SupportTypeResp> list = new ArrayList<>();
        if (CollUtil.isNotEmpty(structureType.getContentType())) list.add(structureType);
        SupportTypeResp instanceType = new SupportTypeResp(
                new TipInfo(DataSourceEnum.INSTANCE.getValue(), DataSourceEnum.INSTANCE.getLabel()),
                dataInstanceDispatcher.uiSupportType());
        if (CollUtil.isNotEmpty(instanceType.getContentType())) list.add(instanceType);
        return list;
    }

    /**
     * 验证数据库连接
     *
     * @param ds 连接信息
     */
    @Override
    public void verify(DataSourcePO ds) {
        //基本验证
        MyVerifyUtil.nullVerify(ds, "数据源不能为空！");
        MyVerifyUtil.nullVerify(ds::getName, "数据源名称不能为空！");
        MyVerifyUtil.nullVerify(ds::getType, "数据源类型不能为空！");
        switch (DataSourceEnum.getEnumByFieldAndCode(ds::getType)) {
            case INSTANCE: {
                DataInstanceService service = dataInstanceDispatcher.getService(ds.getContentType());
                String content = MyVerifyUtil.nullVerify(ds::getContent);
                service.verify(content);
                break;
            }
            case STRUCTURE: {
                String url = MyVerifyUtil.nullVerify(ds::getUrl, "数据源url不能为空！");
                String username = null;
                String password = null;
                DatabaseType dbType = DatabaseType.valueOf(ds.getContentType());
                MyVerifyUtil.nullVerify(dbType, "数据源类型不支持！");
                AutoDDLService adService = autoDDLDispatcher.getService(dbType);
                if (!(DatabaseType.SQLite.name().equals(ds.getContentType()))) {
                    username = MyVerifyUtil.nullVerify(ds::getUsername, "数据源用户名不能为空！");
                    password = MyVerifyUtil.nullVerify(ds::getPassword, "数据源密码不能为空！");
                }
                String key = this.registeredDataSource(dbType, null, ds.getName(), url, username, password);
                adService.verify(ServiceProxy.service(key));
                break;
            }
            default:
                throw BusEx.create("数据源类型不支持！");
        }
    }

    /**
     * 获取转换后的数据
     *
     * @param ds 要转换的对象
     * @return 转换后的json对象
     */
    @Override
    public Object getContent(DataSourcePO ds) {
        this.verify(ds);
        switch (DataSourceEnum.getEnumByFieldAndCode(ds::getType)) {
            case INSTANCE: {
                return dataInstanceDispatcher.getJsonData(ds.getContentType(), ds.getContent());
            }
            case STRUCTURE: {
                return autoDDLDispatcher.getJsonData(ds.getId(), ds.getExclusionTable(), ds.getTablePrefix());
            }
            default:
                throw BusEx.create("数据源类型不支持！");
        }
    }

    /**
     * 注册数据源
     *
     * @param dbType   数据库类型
     * @param id       数据源id
     * @param name     数据源名称
     * @param url      数据源url
     * @param username 数据源用户名
     * @param password 数据源密码
     * @return 数据源注册后的key
     */
    public String registeredDataSource(DatabaseType dbType, String id, String name, String url, String username, String password) {
        id = StrUtil.blankToDefault(id, IdUtil.fastSimpleUUID());
        MyVerifyUtil.nullVerify(url, "数据源url不能为空！");
        AutoDDLService adService = autoDDLDispatcher.getService(dbType);
        try {
            DataSourceHolder.reg(id,
                    com.zaxxer.hikari.HikariDataSource.class.getName(),
                    adService.getContentType().getDriveType().getName(),
                    url,
                    username,
                    password);
        } catch (Exception e) {
            log.error("数据源【{}】注册失败！", name, e);
        }
        log.info("数据源【{}】注册成功！", name);
        return id;
    }
}
